/*
 * Copyright 2011 Andres.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package mx.uacam.balam.client;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import mx.uacam.balam.entities.Descriptor;
import mx.uacam.balam.entities.Part;
import org.apache.commons.lang.RandomStringUtils;

/**
 *
 * @author Andres
 */
public class Client {

    private int port;
    private String address;
    Descriptor descriptor;
    Part parte;
    private String codeClient;

    public Client() {
        this("localhost", 2722);
    }

    public Client(String address, int port) {
        this.address = address;
        this.port = port;
        createCodeClient();
    }

    public void find(String toSearch) {
        setDescriptor(requestInfo(toSearch));
    }

    private Descriptor requestInfo(String fileName) {
        try {
            Socket socket = new Socket(getAddress(), getPort());

            ObjectOutputStream salida = new ObjectOutputStream(socket.getOutputStream());
            ObjectInputStream entrada = new ObjectInputStream(socket.getInputStream());
            
            salida.writeObject(fileName);
            

            try {
                Object readObject = entrada.readObject();

                if (readObject instanceof Descriptor) {
                    Descriptor aDescriptor = (Descriptor) readObject;
                    return aDescriptor;
                }
            } catch (ClassNotFoundException ex) {
                Logger.getLogger(Client.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
            }

            salida.close();
            socket.close();

        } catch (UnknownHostException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
        } catch (IOException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
        }
        return null;
    }

    public void download(String filename) {
        System.out.println(filename);
        for (int i = 0; i < getDescriptor().getNumParts(); i++) {
            String[] url = getDescriptor().getUrl()[i].split(":");
            downloadPart(makeIdPart(i), url[0], Integer.parseInt(url[1]));
        }
    }

    private Part downloadPart(String idPart, String address, int port) {
        try {
            byte[] buf = new byte[10000];
            DatagramSocket ds = new DatagramSocket(getPort());
            try {
                ds.send(new DatagramPacket(idPart.getBytes(), idPart.getBytes().length, InetAddress.getByName(address), port));
            } catch (IOException ex) {
                Logger.getLogger(Client.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
            }
            DatagramPacket dp = new DatagramPacket(buf, buf.length);
            try {
                ds.receive(dp);
                byte[] data = dp.getData();
                int index = Integer.parseInt(splitNamePart(idPart)[0]);
                String name = splitNamePart(idPart)[1];
                double size = 10000;
                //TODO Checar los datos del part
                Part part = new Part(index, name, size, data);
                return part;
            } catch (IOException ex) {
                Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
            }

        } catch (SocketException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
        }
        return parte;
    }

    private String makeIdPart(int index) {//ensambla el ID de las partes
        String filename = descriptor.getFilename();
        return filename + ".00" + index + ".part";
    }

    private String[] splitNamePart(String fileName) {
        String[] split = fileName.split(".0");
        String string = split[0];
        String[] splitExt = split[1].split(".part");

        return new String[]{string, splitExt[0]};
    }

    public static void main(String args[]) {
        Scanner lee = new Scanner(System.in);
        System.out.println("Teclee el nombre del archivo que desea buscar: (nombre completo + extension) ");
        String toFind = lee.next();

        Client x = new Client();
        x.find(toFind);
        x.download(x.getDescriptor().getFilename());

        System.out.println(x.getCodeClient());

    }

    /**
     * 
     * @return 
     */
    public String getAddress() {
        return address;
    }

    /*
     * 
     */
    public void setAddress(String address) {
        this.address = address;
    }

    /**
     * 
     * @return 
     */
    public int getPort() {
        return port;
    }

    /**
     * 
     * @param numPort 
     */
    public void setPort(int port) {
        this.port = port;
    }

    /**
     * 
     */
    private void createCodeClient() {
        codeClient = RandomStringUtils.randomAlphanumeric(6);
    }

    /**
     * 
     * @return 
     */
    public String getCodeClient() {
        return codeClient;
    }

    public Descriptor getDescriptor() {
        return descriptor;
    }

    private void setDescriptor(Descriptor descriptor) {
        this.descriptor = descriptor;
    }
}